`include "common.svh"

module biu (
    input          clk,
    input          rst,
    //Memory Req Port
    input          req_valid,
    input  MEM_REQ req,
    output         req_ready,
    //Memory Rsp Port
    output         rsp_valid,
    output MEM_RSP rsp,
    input          rsp_ready,
    //AXI master interface
    input         axi_awready,
    output        axi_awvalid,
    output [31:0] axi_awaddr,
    // output [ 2:0] axi_awsize,

    input         axi_wready,
    output        axi_wvalid,
    output [63:0] axi_wdata,

    output        axi_bready,
    input         axi_bvalid,

    input         axi_arready,
    output        axi_arvalid,
    output [31:0] axi_araddr,
    // output [ 2:0] axi_arsize,

    output        axi_rready,
    input         axi_rvalid,
    input  [63:0] axi_rdata

);
  // logic [2:0] req_size;
  // MUX_OH #(4,3) mux_req_size(
  //   .din({'d3,'d2,'d1,'d0}),
  //   .sel(req.size),
  //   .dout(req_size)
  // );

  enum logic [1:0] { IDLE,SEND_DATA,RECV_RESP } state,nstate;

  wire req_fire = req_valid & req_ready;
  wire rsp_fire = rsp_valid & rsp_ready;
  /* verilator lint_off UNUSEDSIGNAL */
  MEM_REQ sending_req;
  /* verilator lint_on UNUSEDSIGNAL */
  localparam MEM_REQ_SIZE = $size(MEM_REQ);
  reg_l #(MEM_REQ_SIZE) sending_req_r ( .din(req), .dout(sending_req), .load(req_fire), .*);

  wire send_valid = state == SEND_DATA;
  wire send_ready = axi_wready & axi_rready;
  wire send_fire = send_valid & send_ready;

  assign req_ready = axi_awready & axi_arready & (state == IDLE);
  // assign axi_awsize = req_size;
  assign axi_awvalid = req_valid & (req.cmd == MEM_WRITE) & axi_arready;
  assign axi_awaddr = req.addr[31:0];
  // assign axi_arsize = req_size;
  assign axi_arvalid = req_valid & (req.cmd == MEM_READ) & axi_awready;
  assign axi_araddr = req.addr[31:0];

  assign axi_wvalid = send_valid & (sending_req.cmd == MEM_WRITE) & axi_rready;
  assign axi_wdata = sending_req.data;

  assign axi_bready = rsp_ready;
  assign axi_rready = rsp_ready;
  assign rsp_valid = axi_bvalid | axi_rvalid;

  assign rsp.rob_idx = sending_req.rob_idx;
  assign rsp.prf_idx = sending_req.prf_idx;
  assign rsp.has_data = sending_req.cmd == MEM_READ;
  assign rsp.has_rd = sending_req.has_rd;
  assign rsp.data = axi_rdata;
  reg_r #(2, IDLE) state_r (.din(nstate), .dout(state), .*);

  always_comb begin
    nstate = state;
    case(state)
    IDLE: if(req_fire) nstate = req.cmd == MEM_WRITE ? SEND_DATA : RECV_RESP;
    SEND_DATA: if(send_fire) nstate = RECV_RESP;
    RECV_RESP: if(rsp_fire) nstate = IDLE;
    default: nstate = IDLE;
    endcase
  end

endmodule

